/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.bpm.engine.impl.asyncexecutor;


import com.je.bpm.core.model.TimerEventDefinition;
import com.je.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
import com.je.bpm.engine.impl.persistence.entity.*;
import com.je.bpm.engine.internal.Internal;
import com.je.bpm.engine.runtime.Job;

/**
 * Contains methods that are not tied to any specific job type (async, timer, suspended or deadletter),
 * but which are generally applicable or are about going from one type to another.
 */
@Internal
public interface JobManager {

    /**
     * Execute a job, which means that the logic (async logic, timer that fires, etc)
     * is executed, typically by a background thread of an executor.
     */
    void execute(Job job);

    /**
     * Unacquires a job, meaning that this job was previously locked, and
     * it is now freed to be acquired by other executor nodes.
     */
    void unacquire(Job job);

    /**
     * Creates an async job for the provided {@link ExecutionEntity}, so that
     * it can be continued later in a background thread.
     */
    JobEntity createAsyncJob(ExecutionEntity execution, boolean exclusive);

    /**
     * Schedules and async job. If the {@link AsyncExecutor} is running, it
     * can be executed immediately after the transaction. Otherwise it can
     * be picked up by other executors.
     */
    void scheduleAsyncJob(JobEntity job);

    /**
     * Creates a {@link TimerJobEntity} based on the current {@link ExecutionEntity} and the
     * configuration in the {@link TimerEventDefinition}.
     */
    TimerJobEntity createTimerJob(TimerEventDefinition timerEventDefinition, boolean interrupting, ExecutionEntity execution, String timerEventType, String jobHandlerConfiguration);

    /**
     * Schedules a timer, meaning it will be inserted in the datastore.
     */
    void scheduleTimerJob(TimerJobEntity timerJob);

    /**
     * Moves a {@link TimerJobEntity} to become an async {@link JobEntity}.
     * <p>
     * This happens for example when the due date of a timer is reached,
     * the timer entity then becomes a 'regular' async job that can be
     * picked up by the {@link AsyncExecutor}.
     */
    JobEntity moveTimerJobToExecutableJob(TimerJobEntity timerJob);

    /**
     * Moves an {@link AbstractJobEntity} to become a {@link TimerJobEntity}.
     * <p>
     * This happens for example when an async job is executed and fails.
     * It then becomes a timer, as it needs to be retried later.
     */
    TimerJobEntity moveJobToTimerJob(AbstractJobEntity job);

    /**
     * Moves an {@link AbstractJobEntity} to become a {@link SuspendedJobEntity},
     * such that the {@link AsyncExecutor} won't pick it up anymore for execution.
     */
    SuspendedJobEntity moveJobToSuspendedJob(AbstractJobEntity job);

    /**
     * Transforms a {@link SuspendedJobEntity} back to an {@link AbstractJobEntity}
     * (i.e. to what it was originally). The job will now again be able to
     * picked up by the {@link AsyncExecutor}.
     */
    AbstractJobEntity activateSuspendedJob(SuspendedJobEntity job);

    /**
     * Transforms an {@link AbstractJobEntity} to a {@link DeadLetterJobEntity}.
     * This means that the job has been tried a configurable amount of times,
     * but kept failing.
     */
    DeadLetterJobEntity moveJobToDeadLetterJob(AbstractJobEntity job);

    /**
     * Transforms a {@link DeadLetterJobEntity} to a {@link JobEntity}, thus
     * making it executable again. Note that a 'retries' parameter needs to be passed,
     * as the job got into the deadletter table because of it failed and retries became 0.
     */
    JobEntity moveDeadLetterJobToExecutableJob(DeadLetterJobEntity deadLetterJobEntity, int retries);

    /**
     * The ProcessEngineCongiguration instance will be passed when the {@link ProcessEngine} is built.
     */
    void setProcessEngineConfiguration(ProcessEngineConfigurationImpl processEngineConfiguration);

}
